import {Socket} from "net";
import log from "./logger";
import {axios, EventEmitter, iconv} from "../node-test";
import {Printer} from "./interfaces";
import settings from "./settings";
import * as buffer from "buffer";


// 查询命令是 0x1b76
// /** 打印机状态 */
// /**@{*/
// #define TX_STAT_NOERROR    0x0008 /*无故障*/
// #define TX_STAT_SELECT     0x0010 /*处于联机状态*/
// #define TX_STAT_PAPEREND   0x0020 /*缺纸*/
// #define TX_STAT_BUSY       0x0080 /*繁忙*/
// #define TX_STAT_DRAW_HIGH  0x0100
// #define TX_STAT_COVER      0x0200
// #define TX_STAT_ERROR      0x0400
// #define TX_STAT_RCV_ERR    0x0800 /* Recoverable error */
// #define TX_STAT_CUT_ERR    0x1000 /* Autocutter error */
// #define TX_STAT_URCV_ERR   0x2000 /* Unrecoverable error */
// #define TX_STAT_ARCV_ERR   0x4000 /* Auto-recoverable error */
// #define TX_STAT_PAPER_NE   0x8000 /* paper near-end */
// /**@}*/
// 打印返回
// 32792 0x8018 正常 纸将尽
// 16 12 12 1e
// 32824 0x8038 纸将尽 错误
// 16 32 12 7e
// 24 0x0018 正常
// 16 12 12 12
// 56 0x0038 错误
// 16 32 12 72

const cut = Buffer.from([0x1D, 0x56, 0x01]);
const cr = Buffer.from([0x0A]);
const cr5 = Buffer.from([0x1B, 0x64, 0x05]);
const font0 = Buffer.from([0x1D, 0x21, 0x00]);
const font1 = Buffer.from([0x1D, 0x21, 0x11]);
const alignleft = Buffer.from([0x1B, 0x61, 0x00]);
const aligncenter = Buffer.from([0x1B, 0x61, 0x01]);
const indentleft = Buffer.from([0x1D, 0x4C, 0x20, 0x00]);
const status = Buffer.from([0x1b, 0x76]);

class PrinterImpl extends EventEmitter implements Printer {
    printSock: Socket
    statusSock: Socket
    printerIp = ''
    error = false;
    paperNearEnd = false;

    public constructor() {
        super();
    }

    openPrintSock() {
        // start timeout on open
        const connection_timeout = setTimeout(() => {
            this.printSock.destroy();
            log.error("printSock connection_timeout");
        }, 5000);
        this.printSock.connect(9100, this.printerIp, () => {
            clearTimeout(connection_timeout);
            log.log(`printSock connected to:${this.printerIp}:9100`);
        });
    }

    openStatusSock() {
        // start timeout on open
        const connection_timeout = setTimeout(() => {
            this.statusSock.destroy();
            log.error("statusSock connection_timeout");
        }, 5000);
        this.statusSock.connect(4000, this.printerIp, () => {
            clearTimeout(connection_timeout);
            log.log(`statusSock connected to:${this.printerIp}:4000`);
            // 每一分钟检测一次纸张是否用尽
            setInterval(() => {
                this.statusSock.write(status);
            }, 60 * 1000);
        });
    }

    parser(str: string, index: number) {
        for (let line of str.split("\n")) {
            const cmd = line.split(":")[0];
            const param = line.replace(cmd + ':', '');
            if (cmd === 'font1') {
                this.printSock.write(font1);
            } else if (cmd === 'align-center') {
                this.printSock.write(aligncenter);
            } else if (cmd === 'align-left') {
                this.printSock.write(alignleft);
            } else if (cmd === 'text') {
                this.printSock.write(iconv.encode(param, 'gb18030'));
                this.printSock.write(cr);
            } else if (cmd === 'font0') {
                this.printSock.write(font0);
            } else if (cmd === 'indent-left-20') {
                this.printSock.write(indentleft);
            } else {
                log.error(`命令${cmd}不支持`)
                // throw `命令${cmd}不支持`;
            }
        }
        this.printSock.write(font0);
        const no = ['一', '二', '三', '四', '五', '六', '七'][index];
        this.printSock.write(iconv.encode(`第${no}联`, 'gb18030'));
        this.printSock.write(cr);
        this.printSock.write(cr5);
        this.printSock.write(cut);
    }

    print(count: number, str: string, type: string, paper: any): void {
        if (type === 'needle') {
            for (let i = 0; i < count; i++) {
                this.needle(str, i);
            }
        } else if (type === 'wk') {
            for (let i = 0; i < count; i++) {
                this.wk(str, i, paper);
            }
        } else {
            if (settings.printerSocketDestroy) {
                if (settings.printerIp !== '') {
                    this.printSock = new Socket();
                    this.printSock.connect(9100, settings.printerIp, () => {
                        log.log(`printSock connected to: ${settings.printerIp}:9100, print...`);
                        for (let i = 0; i < count; i++) {
                            this.parser(str, i);
                        }
                        // 查询传送纸传感器状态
                        this.printSock.write(Buffer.from([0x10, 0x04, 0x04]));
                        setTimeout(() => {
                            this.printSock.destroy()
                        }, 2000)
                    });
                    this.printSock.on('data', (data: Buffer) => {
                        log.info("printSock data:", data.toString('hex'));
                    })
                    this.printSock.on('error', function (error) {
                        log.error('printSock error', error);
                    });
                    this.printSock.on('close', () => {
                        log.error('close下线了');
                    });
                }
            } else {
                for (let i = 0; i < count; i++) {
                    this.parser(str, i);
                }
            }
        }
    }

    init() {
        this.printerIp = settings.printerIp;
        log.info('printerIp address:', this.printerIp)
        // 两种打印机，一种是要保持连接，一种是每次打印都需要重新连接
        if (!settings.printerSocketDestroy) {
            if (settings.printerIp !== '') {
                this.printSock = new Socket();
                this.printSock.on('error', function (error) {
                    log.error('printSock error', error);
                });
                this.printSock.on('close', () => {
                    log.error('close下线了');
                    this.printSock.destroy();
                    setTimeout(() => {
                        this.openPrintSock();
                    }, 10 * 1000)
                });
                this.openPrintSock();

                this.statusSock = new Socket();
                this.statusSock.on('error', function (error) {
                    log.error('statusSock error', error);
                });
                this.statusSock.on('data', (msg) => {
                    // log.info('data', msg);
                    if (msg[1] === 0x12 && msg[3] === 0x12) {
                        this.error = false;
                        this.paperNearEnd = false;
                    } else if (msg[1] === 0x32 && msg[3] === 0x72) {
                        this.error = true;
                        this.paperNearEnd = false;
                    } else if (msg[1] === 0x12 && msg[3] === 0x1e) {
                        this.error = false;
                        this.paperNearEnd = true;
                    } else if (msg[1] === 0x32 && msg[3] === 0x7e) {
                        this.error = true;
                        this.paperNearEnd = true;
                    }
                    // 发送事件，用来告警
                    if (this.paperNearEnd) {
                        log.warn("paper_near_end");
                        this.emit("paper_near_end");
                    }
                });
                this.statusSock.on('close', () => {
                    log.error('close下线了');
                    this.statusSock.destroy();
                    setTimeout(() => {
                        this.openStatusSock();
                    }, 10 * 1000)
                });
                this.openStatusSock();
            }
        }
    }

    private needle(str: string, i: number) {
        axios.post("http://localhost:29999", str, {headers: {"Content-Type": "text/plain"}})
            .catch((e) => {
                log.error("print error", e);
            })
    }

    private wk(str: string, i: number, paper: any) {
        paper['html'] = str;
        axios.post("http://localhost:9001/print", paper, {headers: {"Content-Type": "text/json"}})
            .catch((e) => {
                log.error("print error", e);
            })
    }
}

const printer = new PrinterImpl();
export default printer;